package com.system.ad.handler;

import com.alibaba.fastjson.JSON;
import com.system.ad.dump.table.*;
import com.system.ad.index.DataTable;
import com.system.ad.index.IndexAware;
import com.system.ad.index.adplan.AdPlanIndex;
import com.system.ad.index.adplan.AdPlanVo;
import com.system.ad.index.adunit.AdUnitIndex;
import com.system.ad.index.adunit.AdUnitVo;
import com.system.ad.index.creative.CreativeIndex;
import com.system.ad.index.creative.CreativeVo;
import com.system.ad.index.cretiveunit.CreativeUnitIndex;
import com.system.ad.index.cretiveunit.CreativeUnitVo;
import com.system.ad.index.district.DistrictIndex;
import com.system.ad.index.interest.UnitItIndex;
import com.system.ad.index.keyword.KeyWordIndex;
import com.system.ad.mysql.constant.OpType;
import com.system.ad.utlis.CommonUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 索引数据处理器
 * 1. 索引之间存在着层级的划分, 也就是依赖关系的划分
 * 2. 加载全量索引其实是增量索引 "添加" 的一种特殊实现
 * Created by Qinyi.
 */
@Slf4j
public class AdLevelDataHandler {

    /**
     * 处理索引层级为2的数据
     * @param planTable 推广计划表
     * @param type 操作类型
     */
    public static void handleLevel2(AdPlanTable planTable, OpType type) {
        AdPlanVo planObject = new AdPlanVo(
                planTable.getId(),
                planTable.getUserId(),
                planTable.getPlanStatus(),
                planTable.getStartDate(),
                planTable.getEndDate()
        );
        handleBinlogEvent(
                DataTable.of(AdPlanIndex.class),
                planObject.getPlanId(),
                planObject,
                type
        );
    }

    /**
     * 处理索引层级为2的数据
     * @param creativeTable 创意表
     * @param type 操作类型
     */
    public static void handleLevel2(AdCreativeTable creativeTable, OpType type) {
        CreativeVo creativeObject = new CreativeVo(
                creativeTable.getAdId(),
                creativeTable.getName(),
                creativeTable.getType(),
                creativeTable.getMaterialType(),
                creativeTable.getHeight(),
                creativeTable.getWidth(),
                creativeTable.getAuditStatus(),
                creativeTable.getAdUrl()
        );
        handleBinlogEvent(
                DataTable.of(CreativeIndex.class),
                creativeObject.getAdId(),
                creativeObject,
                type
        );
    }

    /**
     * 处理索引层级为3的数据
     * @param unitTable 推广单元表
     * @param type 操作类型
     */
    public static void handleLevel3(AdUnitTable unitTable, OpType type) {
        AdPlanVo adPlanObject = DataTable.of(AdPlanIndex.class).get(unitTable.getPlanId());
        if (adPlanObject == null) {
            log.error("handleLevel3 found AdPlanObject error: {}", unitTable.getPlanId());
            return;
        }

        AdUnitVo unitObject = new AdUnitVo(
                unitTable.getUnitId(),
                unitTable.getUnitStatus(),
                unitTable.getPositionType(),
                unitTable.getPlanId()
        );

        handleBinlogEvent(
                DataTable.of(AdUnitIndex.class),
                unitTable.getUnitId(),
                unitObject,
                type
        );
    }

    /**
     * 处理索引层级为3的数据
     * @param creativeUnitTable 创意与推广单元关联表
     * @param type 操作类型
     */
    public static void handleLevel3(AdCreativeUnitTable creativeUnitTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("CreativeUnitIndex not support update");
            return;
        }

        AdUnitVo unitObject = DataTable.of(AdUnitIndex.class).get(creativeUnitTable.getUnitId());
        CreativeVo creativeObject = DataTable.of(CreativeIndex.class).get(creativeUnitTable.getAdId());

        if (unitObject == null || creativeObject == null) {
            log.error("AdCreativeUnitTable index error: {}", JSON.toJSONString(creativeUnitTable));
            return;
        }

        CreativeUnitVo creativeUnitObject = new CreativeUnitVo(
                creativeUnitTable.getAdId(),
                creativeUnitTable.getUnitId()
        );
        handleBinlogEvent(
                DataTable.of(CreativeUnitIndex.class),
                CommonUtils.stringConcat(
                        creativeUnitObject.getAdId().toString(),
                        creativeUnitObject.getUnitId().toString()
                ),
                creativeUnitObject,
                type
        );
    }

    /**
     * 处理索引层级为4的数据（地域限制）
     * @param unitDistrictTable 推广单元地域限制表
     * @param type 操作类型
     */
    public static void handleLevel4(AdUnitDistrictTable unitDistrictTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("district index can not support update");
            return;
        }

        AdUnitVo unitObject = DataTable.of(AdUnitIndex.class).get(unitDistrictTable.getUnitId());
        if (unitObject == null) {
            log.error("AdUnitDistrictTable index error: {}", unitDistrictTable.getUnitId());
            return;
        }

        String key = CommonUtils.stringConcat(
                unitDistrictTable.getProvince(),
                unitDistrictTable.getCity()
        );
        Set<Long> value = new HashSet<>(Collections.singleton(unitDistrictTable.getUnitId()));
        handleBinlogEvent(
                DataTable.of(DistrictIndex.class),
                key,
                value,
                type
        );
    }

    /**
     * 处理索引层级为4的数据（兴趣限制）
     * @param unitItTable 推广单元兴趣限制表
     * @param type 操作类型
     */
    public static void handleLevel4(AdUnitItTable unitItTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("it index can not support update");
            return;
        }

        AdUnitVo unitObject = DataTable.of(AdUnitIndex.class).get(unitItTable.getUnitId());
        if (unitObject == null) {
            log.error("AdUnitItTable index error: {}", unitItTable.getUnitId());
            return;
        }

        Set<Long> value = new HashSet<>(Collections.singleton(unitItTable.getUnitId()));
        handleBinlogEvent(
                DataTable.of(UnitItIndex.class),
                unitItTable.getItTag(),
                value,
                type
        );
    }

    /**
     * 处理索引层级为4的数据（关键词限制）
     * @param keywordTable 推广单元关键词限制表
     * @param type 操作类型
     */
    public static void handleLevel4(AdUnitKeywordTable keywordTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("keyword index can not support update");
            return;
        }

        AdUnitVo unitObject = DataTable.of(AdUnitIndex.class).get(keywordTable.getUnitId());
        if (unitObject == null) {
            log.error("AdUnitKeywordTable index error: {}", keywordTable.getUnitId());
            return;
        }

        Set<Long> value = new HashSet<>(Collections.singleton(keywordTable.getUnitId()));
        handleBinlogEvent(
                DataTable.of(KeyWordIndex.class),
                keywordTable.getKeyword(),
                value,
                type
        );
    }

    /**
     * 处理增量操作
     * @param index 索引
     * @param key 键
     * @param value 值
     * @param type 操作类型
     * @param <K> 键类型
     * @param <V> 值类型
     */
    private static <K, V> void handleBinlogEvent(
            IndexAware<K, V> index,
            K key,
            V value,
            OpType type) {
        switch (type) {
            case ADD:
                index.add(key, value);
                break;
            case UPDATE:
                index.update(key, value);
                break;
            case DELETE:
                index.delete(key, value);
                break;
            default:
                break;
        }
    }
}
